#ifndef RELATIONSHIPSVIEW_H
#define RELATIONSHIPSVIEW_H

#include <QGraphicsView>
#include <QGraphicsWidget>
#include <QGraphicsEffect>
#include <QTimer>
#include <QGraphicsLinearLayout>

#include <dynamicmodel.h>
#include <viewwidget.h>
#include <viewinterface.h>

class ArrowItem;
typedef QList<ArrowItem *> ArrowItemList;

class FormItem : public QGraphicsObject
{
    Q_OBJECT

public:
    enum HighlightMode
    {
        HighlightNone,
        HighlightHovered,
        HighlightSource,
        HighlightDest,
        HighlightSourceDest
    };

    static const int FixedHeight = 32;

    FormItem(ARSDummyForm * form, QGraphicsItem * parent = 0);

    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    ARSDummyForm * form() const;
    ArrowItemList & inArrows();
    void addInArrow(ArrowItem * item);
    ArrowItemList & outArrows();
    void addOutArrow(ArrowItem * item);
    QVariant itemChange( GraphicsItemChange change, const QVariant & value );
    bool isRelated(FormItem * item);
    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
    void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
    void setHighlightMode(HighlightMode mode);

public slots:
    void updateArrows();

private:
    QPixmap generatePixmap(const QImage & source, QSize size);

    ARSDummyForm * m_form;
    QFont m_font;
    ArrowItemList m_inArrows;
    ArrowItemList m_outArrows;
    QHash<HighlightMode, QPixmap> m_pixmaps;
    HighlightMode m_highlightMode;
};

typedef QList<FormItem *> FormItemList;

class ReltionDetailItem;

class ArrowItem : public QGraphicsObject
{
    Q_OBJECT

public:
    enum HighlightFactor
    {
        HighlightNone = 0,
        HighlightIn = 1,
        HighlightOut = 2,
        HighlightHovered
    };

    ArrowItem(QGraphicsItem * parent, QGraphicsScene * scene);
    void setHighlightFactor(HighlightFactor factor);
    void setItemList(const ARSExecItemList & list);
    const ARSExecItemList & itemList()const;

    virtual FormItem * from() const = 0;
    virtual FormItem * to() const = 0;
    virtual void updateGeometry() = 0;

signals:
    void detailsClicked(ArrowItem * arrow, QRect parentRect);


public slots:
    void detailsItemClicked();
    void hovered(bool yes);

protected:
    ArrowItem::HighlightFactor m_highlightFactor;
    QHash<ArrowItem::HighlightFactor, QPen> m_colors;
    ReltionDetailItem * m_detailItem;
    ARSExecItemList m_itemList;
};

class ArrowItemLoop : public ArrowItem
{
    Q_OBJECT

public:
    ArrowItemLoop(FormItem * form, QGraphicsItem * parent, QGraphicsScene * scene);

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    FormItem * from() const;
    FormItem * to() const;
    void updateGeometry();
    QRectF boundingRect() const;

private:
    FormItem * m_formItem;
    QRectF m_rect;
};

class ArrowItemLine : public ArrowItem
{
    Q_OBJECT

public:
    ArrowItemLine(FormItem * from, FormItem * to, QGraphicsItem * parent, QGraphicsScene * scene);

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    FormItem * from() const;
    FormItem * to() const;
    void updateGeometry();
    QRectF boundingRect() const;

private:
    QPointF intersectPoint(QLineF line, QRectF rect);
    FormItem * m_from;
    FormItem * m_to;
    QLineF m_line;
};

class ReltionDetailButton : public QGraphicsWidget
{
    Q_OBJECT

public:
    ReltionDetailButton(const QPixmap & pixmap, const QPixmap & hoverPixmap, QGraphicsItem * parent);

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);

signals:
    void clicked();

private:
    QPixmap m_pixmap;
    QPixmap m_hoverPixmap;
};

class ReltionDetailLabel : public QGraphicsWidget
{
    Q_OBJECT

public:
    ReltionDetailLabel(int count, QGraphicsItem * parent);

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void setCount(int count);
    void setCurrentIndex(int index);

private:
    int m_count;
    int m_currentIndex;
};

class ReltionDetailTitle : public QGraphicsWidget
{
    Q_OBJECT

public:
    static const int FixedHeight = 22;

    ReltionDetailTitle(QGraphicsItem * parent);
    void setCount(int count);
    void setCurrentPage(int index);

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

public slots:
    void nextPage();
    void previousPage();

signals:
    void pageChanged(int index);
    void closeClicked();

private:
    int m_count;
    int m_currentPage;
    ReltionDetailLabel * m_label;
};

class ReltionDetailItemView : public QGraphicsPixmapItem
{
public:
    ReltionDetailItemView(QGraphicsItem *parent);

    ARSExecItem * item() const;
    void setItem(ARSExecItem * item);
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

private:
    ARSExecItemList generateItemList(ARSExecItem * item);
    void generatePixmap(const ARSExecItemList & list, QSize size);
    QSize countSize(const ARSExecItemList & list) const;

    ARSExecItem * m_item;
};

class ReltionDetailItem : public QGraphicsObject
{
    Q_OBJECT
    Q_PROPERTY(qreal animProcess READ animProcess WRITE setAnimProcess)

public:
    enum State
    {
        Collapsed,
        Expanded,
        Animated
    };

    ReltionDetailItem(QGraphicsItem * parent);

    void setHighlightFactor(ArrowItem::HighlightFactor factor);
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void setItemList(const ARSExecItemList & list);
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void setExpanded(bool expanded);
    qreal animProcess() const;
    void setAnimProcess(qreal process);
    QRectF boundingRect() const;
    void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
    void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);

signals:
    void detailsClicked();
    void hovered(bool yes);

public slots:
    void expandFinished();
    void collapseFinished();
    void setPage(int index);
    void collapse();

private:
    static const int margin = 4;

    QRectF itemRect()const;

    ArrowItem::HighlightFactor m_highlightFactor;
    QHash<ArrowItem::HighlightFactor, QPixmap> m_pixmaps;
    ARSExecItemList m_itemList;
    State m_state;
    qreal m_animProcess;

    ReltionDetailTitle * m_title;
    ReltionDetailItemView * m_itemView;
    QGraphicsDropShadowEffect * m_shadow;
    QHash<ArrowItem::HighlightFactor, QPen> m_borderPens;
};

class RelationshipsView : public QGraphicsView
{
    Q_OBJECT

public:
    RelationshipsView(QWidget * parent = 0);
    void setModel(DynamicModel * model);

//public slots:
//    void animate();

private:
    void findRelations();
    FormItem * formItem(ARSDummyForm * form);
//    QLine force(FormItem * item);

    DynamicModel * m_model;
    FormItemList m_formList;
    ArrowItemList m_arrowList;

    QTimer * m_timer;
};

class RelationshipsViewWidget : public DynamicViewWidget
{
    Q_OBJECT

public:
    RelationshipsViewWidget(QWidget * parent);

    QString pluginName() const;
    void connectToolBarItems(const ToolBarItemList & items);
    void disconnectToolBarItems(const ToolBarItemList & items);
    void adjustToolbar(const ToolBarItemList & itemsList) const;
    void setModel(DynamicModel * model);

signals:
    void openItem(ARSExecItem * item);

private:
    RelationshipsView * m_view;
};

class RelationshipsViewPlugin : public QObject,
                                public ViewPluginInterface
{
    Q_INTERFACES(PluginInterface ViewPluginInterface)
    Q_OBJECT

public:
    RelationshipsViewPlugin(QObject * parent = 0);

    QString name()const;
    QString description()const;
    bool loadSettings();
    QString viewName()const;
    ViewWidget::ViewType viewType() const;
    QIcon icon(bool active)const;
    ViewWidget * createView(QWidget * parent = 0)const;
    ToolBarItemList toolBarItems(QObject * parent)const;
    SettingsWidget * settingsWidget(QWidget * parent = 0)const;
    void appEvent(AppEvent * event);
};

#endif // RELATIONSHIPSVIEW_H
